#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "FileReader.h"
#include "include.h"

char * FileReader::GetNextTag(FILE * fptr)
{
	//char * buf = (char *)malloc(sizeof(char) * 
	char c;
	fpos_t startPtr; 
	int startIndex = 0;
	int endIndex = 0;
	int count = 0;
	bool started = false;
	bool ended = false;
	while(fread(&c, sizeof(char), 1, fptr) == 1)
	{
		if(c == '<')
		{
			fgetpos(fptr, &startPtr);
			startIndex = count;
			started = true;
		}
		if(c == '>' && started)
		{
			endIndex = count;
			ended = true;
			break;
		}
		count ++;
	}
	
	if(!started || !ended)
	{
		return NULL;
	}

	fsetpos(fptr, &startPtr);
	fseek(fptr,-1, SEEK_CUR);
	int stringSize = endIndex - startIndex + 1;
	char * buf = (char *) malloc(sizeof(char) * stringSize + 1);
	fread(buf, sizeof(char),stringSize, fptr);
	buf[stringSize] = '\0';
	return buf;
}		

char * FileReader::GetNextElement(char * tag, int * pos)
{
	if(tag == NULL)
		return NULL;
		
	int startIndex = *pos;
	if(tag[startIndex] == '\0')
		return NULL;
	int endIndex = 0;
	int openparen = 0;
	bool openQuote = false;
	int stringSize = 0;
	int stringLen = strlen(tag);
	bool closeElement = false;
	for(int i = startIndex; i < stringLen; i++)
	{
		
		if(tag[i] == '<')
			startIndex = i+1;
		if(tag[i] == '(')
			openparen++;
		if(tag[i] == ')' && openparen > 0)
			openparen--;
		if(tag[i] == '"')
		{
			openQuote = !openQuote;
			printf("openQuote = %d\n", openQuote);
		}
			
		if(!openQuote && openparen == 0 && (tag[i] == ',' || tag[i] == '>'))
		{
			endIndex = i - 1;
			*pos = i+1;
			closeElement = true;
			break;
		}
		if(tag[i] == '\0')
			return NULL;
		if(openQuote || (tag[i] != '<' && tag[i] != ' ' && tag[i] != '\t' && tag[i] != '\n'))
		{
			stringSize ++;
		}
	}
	if(!closeElement)
		return NULL;
	char * buf = (char *) malloc(sizeof(char) * stringSize+1);
	int count = 0;
	openQuote = false;
	for(int i = startIndex; i <= endIndex && count < stringSize; i++)
	{
		
		if(tag[i] == '"')
			openQuote = !openQuote;
		
		if(openQuote || (tag[i] != ' ' && tag[i] != '\t' && tag[i] != '\n'))
		{
			buf[count] = tag[i];
			count++;
		}
	}
	buf[stringSize] = '\0';
	return buf;
}
Vector2D FileReader::ReadCoordinate(char * element)
{
	Vector2D coord;
	if(sscanf(element, "(%f,%f)", &(coord.x), &(coord.y))!= 2)
	{
		printf("Error reading coordinate %s\n", element);
	}
	return coord;
}
float FileReader::ReadFloat(char * element)
{
	float num;
	if(sscanf(element, "%f", &num)!= 1)
	{
		printf("Error reading float %s\n", element);
	}
	return num;
}
int FileReader::ReadInt(char * element)
{
	int num;
	if(sscanf(element, "%d", &num)!= 1)
	{
		printf("Error reading integer %s\n", element);
	}
	return num;
}
Vector2D FileReader::ReadNextCoordinate(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	Vector2D c = ReadCoordinate(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return c;
}
int FileReader::ReadNextInt(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	int i = ReadInt(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return i;
}
float FileReader::ReadNextFloat(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	float f = ReadFloat(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return f;
}
char * FileReader::ReadNextString( char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	return element;
}
char * FileReader::ReadDictionaryEntry(char * element)
{
	char dictionaryEntry[64];
		
	if(sscanf(element,"~%s",dictionaryEntry) == 1)
	{
		char * str = (char *)malloc(sizeof(char)*(strlen(dictionaryEntry)+1));
		strcpy(str, dictionaryEntry);
		return str;
	}
	return NULL;
}
TypedValue * FileReader::ReadTypedValue(char * element)
{
	char type[16];
	char * value = (char *)malloc(sizeof(char)*256);
	
	if(sscanf(element,"(%[A-Z],%[^)])",type, value) == 2)
	{
		if(strcmp(type,INT_TYPE_STRING) == 0)
		{
			int * i = (int *)malloc(sizeof(int)); 
			sscanf(value,"%d",i);
			delete(value);
			value = NULL;
			printf("making int TypedValue %d\n", *i);
			return new TypedValue((void *)i, type);
		}
		else if(strcmp(type,FLOAT_TYPE_STRING) == 0)
		{
			float * f = (float *)malloc(sizeof(float)); 
			sscanf(value,"%f",f);
			printf("making float TypedValue %f\n", *f);
			delete(value);
			value = NULL;
			return new TypedValue((void *)f, type);
		}
		else if(strcmp(type,STRING_TYPE_STRING) == 0)
		{
			printf("making string TypedValue %s\n", value); 
			return new TypedValue((void *)value, type);
		}
		else if(strcmp(type, BOOL_TYPE_STRING) == 0)
		{
			bool * b = (bool *)malloc(sizeof(bool));
			if(strcmp(value, "TRUE") == 0 || strcmp(value, "true") == 0)
			{
				*b = true;
			}
			else
			{
				*b = false;	
			}
			printf("making bool TypedValue %d\n", *b);
			return new TypedValue((void *)b, type);
		}
	}
	return NULL;
}
BooleanStatement * FileReader::ReadBooleanStatement(char * element)
{
	printf("strlen(element)=%d\n",strlen(element));
	printf("Want to read boolean statement = %s\n",element);
	char operation[64];
	char * remainder = (char *)malloc(sizeof(char) * (strlen(element)+1));
	printf("Reading Boolean Statement = %s\n", element);
	if(sscanf(element, "%[A-Z](%s", operation, remainder) == 2)
	{
		printf("operation = %s, remainder = %s\n", operation, remainder);
		
		int pos = 0;
		char * arg1 = GetNextElement(remainder, &pos);
		char * arg2 = (char *)malloc(sizeof(char) * (strlen(remainder) - pos));
		strncpy(arg2, remainder + pos, strlen(remainder) - pos-1);
		printf("remainder length = %d\n",strlen(remainder));
		printf("pos = %d\n", pos);
		arg2[strlen(remainder) - pos-1] = '\0';
		printf("arg1 = %s\n", arg1);
		printf("arg2 = %s\n", arg2);
		
		BooleanStatement * bs1 = NULL;
		TypedValue * tv1 = NULL;
		char * de1 = NULL;
		if(!(bs1 = ReadBooleanStatement(arg1)))
		{
			if(!(tv1 = ReadTypedValue(arg1)))
			{
				if(!(de1 = ReadDictionaryEntry(arg1)))
					return NULL;	
			}
		}
		
		BooleanStatement * bs2 = NULL;
		TypedValue * tv2 = NULL;
		char * de2 = NULL;
		if(!(bs2 = ReadBooleanStatement(arg2)))
		{
			if(!(tv2 = ReadTypedValue(arg2)))
			{
				if(!(de2 = ReadDictionaryEntry(arg2)))
					return NULL;
			}
		}
		if(arg1)
		{
			delete(arg1);
			arg1 = NULL;
		}
		if(arg2)
		{
			delete(arg2);
			arg2 = NULL;
		}
		if(bs1)
		{
			if(bs2)
			{
				return new BooleanStatement(operation, bs1, bs2);
			}
			else if(tv2)
			{
				return new BooleanStatement(operation, bs1, tv2);
			}
			else
			{
				return new BooleanStatement(operation, bs1, de2);
			}
				
		}
		else if(tv1)
		{
			if(bs2)
			{
				return new BooleanStatement(operation, tv1, bs2);
			}
			else if(tv2)
			{
				return new BooleanStatement(operation, tv1, tv2);
			}
			else
			{
				return new BooleanStatement(operation, tv1, de2);
			}
		}
		else
		{
			if(bs2)
			{
				return new BooleanStatement(operation, de1, bs2);
			}
			else if(tv2)
			{
				return new BooleanStatement(operation, de1, tv2);
			}
			else
			{
				return new BooleanStatement(operation, de1, de2);
			}
		}
	}
	if(remainder)
	{
		delete(remainder);
		remainder = NULL;
	}
	return NULL;
}
BooleanStatement * FileReader::ReadNextBooleanStatement(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	BooleanStatement * statement = ReadBooleanStatement(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return statement;
}
NavigationEdge * FileReader::ReadNextNavigationEdge(char * tag, int * pos)
{
	Vector2D ep1 = ReadNextCoordinate(tag, pos);
	Vector2D ep2 = ReadNextCoordinate(tag, pos);
	char * r2lLocomotion = ReadNextString(tag,pos);
	char * l2rLocomotion = ReadNextString(tag,pos);
	int numTags = ReadNextInt(tag,pos);
	char ** behaviorTags = (char**)malloc(sizeof(char*)*numTags);
	for(int i=0; i < numTags; i++)
	{
		char * bTag = ReadNextString(tag,pos);
		printf("tag %d = %s\n", i, bTag);
		behaviorTags[i] = bTag;
	}
	Locomotion r2l = walk;
	if(strcmp(r2lLocomotion,"jump")==0)
		r2l = jump;
	Locomotion l2r = walk;
	if(strcmp(l2rLocomotion,"jump")==0)
		l2r = jump;	
	return new NavigationEdge(ep1, ep2,r2l, l2r,behaviorTags, numTags);
}
ConditionalStatement * FileReader::ReadNextConditionalStatement(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	ConditionalStatement * statement = ReadConditionalStatement(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return statement;
}
ConditionalStatement * FileReader::ReadConditionalStatement(char * element)
{
	char * remainder = (char *)malloc(sizeof(char) * (strlen(element)+1));
	printf("Reading Conditional Statement = %s\n", element);
	
	if(sscanf(element,"IF(%s", remainder) == 1)
	{
		printf("remainder = %s\n",remainder);
		int pos = 0;
		char * arg1 = GetNextElement(remainder, &pos);
		printf("pos = %d", pos);
		char * arg2 = GetNextElement(remainder, &pos);
		printf("pos = %d", pos);
		char * arg3 = (char *)malloc(sizeof(char) * (strlen(remainder) + 1 - pos));

		sscanf(remainder+ pos, "%[^)])", arg3);
		arg3[strlen(remainder) - pos] = '\0';
		
		printf("arg1 = %s\n", arg1);
		printf("arg2 = %s\n", arg2);
		printf("arg3 = %s\n", arg3);
		
		BooleanStatement * bs = ReadBooleanStatement(arg1);
		if(bs && arg2 && arg3)
		{
			ConditionalStatement * thenConditional = ReadConditionalStatement(arg2);
			ConditionalStatement * elseConditional = ReadConditionalStatement(arg3);
			char * thenString = NULL;
			char * elseString = NULL;
			if(!thenConditional)
			{
				thenString = ReadDictionaryEntry(arg2);
			}
			if(!elseConditional)
			{
				elseString = ReadDictionaryEntry(arg3);
			}
			
			if(thenConditional)
			{
				if(elseConditional)
				{
					return new ConditionalStatement(bs, thenConditional,elseConditional);
				}
				else if(elseString)
				{
					return new ConditionalStatement(bs, thenConditional, elseString);
				}
			}
			else if(thenString)
			{
				if(elseConditional)
				{
					return new ConditionalStatement(bs, thenString,elseConditional);
				}
				else if(elseString)
				{
					return new ConditionalStatement(bs, thenString, elseString);
				}
			}
		}
		if(arg1)
		{
			delete(arg1);
			arg1 = NULL;
		}
		if(arg2)
		{
			delete(arg2);
			arg2 = NULL;
		}
		if(arg3)
		{
			delete(arg3);
			arg3 = NULL;
		}
	}
	if(remainder)
	{
		delete(remainder);
		remainder = NULL;
	}
	return NULL;
}
Vector2D * FileReader::ReadNextVectorArray(int numVertices, char * tag, int * pos)
{
	Vector2D * vertices = (Vector2D *)malloc(sizeof(Vector2D) * numVertices);
	for(int i = 0; i < numVertices; i++)
	{
		vertices[i] = ReadNextCoordinate(tag, pos);
	}
	return vertices;
}
